#pragma once

#define PATH_MAX 1000

#define MAX_FIELD 51

// number of pieces up to which we build databases.
#define MAXPIECES 8
// maximal number of a single piece - with this definition,
// if you build the 7-piece database, it will generate 4-3 but not 5-2. 
// for the 8-piece it will just generate the 4-4 database
// WARNING! the current code will not work for MAXPIECE > 4!
// NOT ANY MORE!
//#define MAXPIECE ((MAXPIECES+1)/2)
#define MAXPIECE 5


// data types used in end game database generator
#define int8      __int8
#define uint8     unsigned __int8
#define int16     __int16
#define uint16    unsigned __int16
#define int32     __int32
#define uint32    unsigned __int32
#define int64     __int64
#define uint64    unsigned __int64



// declaration of bitboard position
struct BitBoard
{
	typedef uint32 value_type;
	volatile uint32 wm;
	volatile uint32 bm;
	volatile uint32 wk;
	volatile uint32 bk;
	int score;
};

struct BitBoard64
{
	typedef uint64 value_type;
	volatile uint64 wm;
	volatile uint64 bm;
	volatile uint64 wk;
	volatile uint64 bk;
	int score;
	uint8 length;
};


typedef BitBoard BitBoardMove;
typedef BitBoard64 BitBoardMove64;

// types of supported checkers
enum eCheckersType { CzechCheckers, InternationalCheckers, EnglishCheckers, UnknownType };

// PDN codes of draughts types
#define PDN_CODE_UNKNOWN				-1
#define PDN_CODE_CZECH					29
#define PDN_CODE_INTERNATIONAL			20
#define PDN_CODE_ENGLISH				21	

// conversion routines among draughts types

eCheckersType inline PDNCodeToEnum(int32 code)
{
	switch(code)
	{
	case PDN_CODE_CZECH:
		return CzechCheckers;
	case PDN_CODE_ENGLISH:
		return EnglishCheckers;
	case PDN_CODE_INTERNATIONAL:
		return InternationalCheckers;
	default:
		assert(false);
		return UnknownType;
	}
}

int32 inline EnumToPDNCode(eCheckersType draughtsType)
{
	switch(draughtsType)
	{
	case CzechCheckers:
		return PDN_CODE_CZECH;
	case EnglishCheckers:
		return PDN_CODE_ENGLISH;
	case InternationalCheckers:
		return PDN_CODE_INTERNATIONAL;
	default:
		assert(false);
		return PDN_CODE_UNKNOWN;
	}
}


// colors of sides
#define BLACK 0
#define WHITE 1
#define CC 1

// database scores 
#define UNKNOWN 0
#define WIN 1
#define LOSS 2
#define DRAW 3

#define ZOBRIST_KEY unsigned __int64



//------------------------------------------------------------------------
// macros

#define Pad16(x) (((x)/16+1)*16)
#define HiWord(x) (((x)&0xFFFF0000)>>16)
#define LoWord(x) ((x)&0xFFFF)
#define HiDWordHiWord(x) (((x)&0xFFFF000000000000)>>(16+32))
#define HiDWordLoWord(x) (((x)&0x0000FFFF00000000)>>32)


//------------------------------------------------------------------------
// Global Engine Data Structure

struct CacheItem;
struct CacheItem64;
struct EvalCacheItem;

#define MAX_DEPTH		99
#define MAX_KILLER		2

#define MAX_GAME_LENGTH 1000

const int iTableSize = 51;

struct RepetitionRecord
{
	ZOBRIST_KEY zkeyBoard;
	int iOccurence;
};


namespace DbReader
{
	template<int MaxPieces, int MaxPiece, int MaxRank> class CDbReader;
}

// constants for Czech Checkers
// for International Checkers make upgrade of MaxRank
#define EGTB_MAX_PIECES				8
#define EGTB_MAX_PIECE				5
#define EGTB_MAX_RANK				7


// local instance engine data
struct SEngineData
{
	// EGTB Reading Access Object
	DbReader::CDbReader<EGTB_MAX_PIECES, EGTB_MAX_PIECE, EGTB_MAX_RANK>* pReader;


	// start-up thinking information
	volatile eCheckersType CheckersType;
	BitBoard bbStartPosition;
	BitBoard64 bbStartPosition64;
	volatile bool bWhiteTurn;
	BitBoard bbBestMove;
	BitBoard64 bbBestMove64;

	// search type
	volatile DWORD dwSearchType;
	volatile DWORD dwComputingTime;
	volatile DWORD dwMaxDepth;

	// configuration variables
	volatile int iCacheSizeMB;
	// TO-DO: it will be set when DbReader will retransformed to the reentrant class with shared file access
	// multithreading will be done by locking file access read
	// volatile int iTableBaseSizeMB; 
	volatile bool bUseCache;
	volatile bool bUseHistoryTables;
	volatile bool bUseKillerMoves;
	volatile bool bUseEndGameDB;
	volatile bool bUsePositionEvaluation;
	volatile bool bEngineReportProgress;

	// progress variables
	volatile DWORD dwStartTime;
	volatile DWORD dwTerminateTime;
	volatile DWORD dwMaxTime;
	volatile DWORD dwLastProgressTime;
	volatile DWORD dwProgressTimeStep;

	// output engine info
	volatile int iMaxDepth;
	volatile int iReachedDepth;
	volatile int iReachedCalmPosDepth;
	volatile long iNumberOfNodes;
	volatile long iNodesPerSec;
	volatile long iCacheHit;
	volatile long iCacheMiss;

	// termination flag
	bool volatile bTerminationFlag;

	// EGTB initialization variables
	wchar_t szEGTBPath[MAX_PATH];
	volatile int iEndGameCacheSizeInMB;

	// function pointers
	int (*MoveGenerator32Ptr)(BitBoard* bb, bool bWhite, BitBoard* movelist);
	int (*MoveGenerator64Ptr)(BitBoard64* bb, bool bWhite, BitBoard64* movelist);

	bool (*TestJump32Ptr)(BitBoard* bb, bool bWhite);
	bool (*TestJump64Ptr)(BitBoard64* bb, bool bWhite);

	int (*Evaluation32Ptr)(SEngineData *ed, BitBoard* bb, bool bWhite);
	int (*Evaluation64Ptr)(SEngineData *ed, BitBoard64* bb, bool bWhite);

	bool (*IsDrawPtr32)(SEngineData *ed, BitBoard* bb, ZOBRIST_KEY zkeyBoard);
	bool (*IsDrawPtr64)(SEngineData *ed, BitBoard64* bb, ZOBRIST_KEY zkeyBoard);

	// evaluation parameters
	int* wPieceSquareTable;		// piece square evalution for men
	int* bPieceSquareTable;		// piece square evaluation for men

	// transposition table variables
	CacheItem* g_Cache;
	CacheItem* g_Cache2;	// two-level cache
	CacheItem64* g_Cache64;
	long g_CacheItemCount;
	long g_CacheMask;

	EvalCacheItem* g_EvalCache;
	long g_EvalCacheItemCount;
	long g_EvalCacheMask;

	// killer-moves array
	ZOBRIST_KEY keyKillers[MAX_DEPTH][MAX_KILLER];

	// history heuristics
	int HistoryTable[iTableSize][iTableSize][2];

	// draw-detection members
	ZOBRIST_KEY positionStack[MAX_GAME_LENGTH];
	int drawPositionCount;
	RepetitionRecord repRecord[MAX_GAME_LENGTH];

	// report-progress function data 
	void* pReportFuncData;

	// function pointer for the progress function
	void (*EnginePercentProgress)(int percent, void* pData);
};
